﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using G.Net.Oauth;
using G.Net;
using System.Collections.Generic;
using Microsoft.Phone.Controls;
using System.Security.Cryptography;
using TianYa.API.Parser;

namespace TianYa.API
{
    public class DefaultClient
    {
        #region Login
        private void GetRequestToken(Action<OAuthRequestToken> callback)
        {
            var requester = new TokenObtainRequest("http://open.tianya.cn/oauth/request_token.php");
            requester.Request((status, msg) =>
            {
                if (status == WebExceptionStatus.Success)
                {
                    var match = ParseQuesrString(msg);
                    //if (!match.Success)
                    //    throw new Exception("Failed to retrieve request token from the web response.");
                    var requestToken = match["oauth_token"];
                    var requestTokenSecret = match["oauth_token_secret"];
                    callback(new OAuthRequestToken() { Token = requestToken, Secret = requestTokenSecret });
                }
                else
                    callback(null);
            });
        }

        private const string callbackurl = "http://ghwghw4.com";
        public void Login(Action<OAuthAccessToken> callback)
        {
            this.GetRequestToken((c) =>
            {
                Deployment.Current.Dispatcher.BeginInvoke(() =>
                {
                    if (c != null)
                    {
                        G.Controls.ChildWindow childwindow = new G.Controls.ChildWindow();
                        WebBrowser web = new WebBrowser();
                        web.IsScriptEnabled = true;
                        web.Navigate(new Uri(string.Format("http://open.tianya.cn/oauth/authorize.php?oauth_token={0}&consumer_key={1}&oauth_callback={2}", c.Token, G.Net.Oauth.OauthConfiger.AppKey, HttpUtility.UrlEncode(callbackurl))));
                        childwindow.Content = web;
                        childwindow.IsOpen = true;
                        web.Navigating += (s, e) =>
                        {
                            if (e.Uri.OriginalString.StartsWith(callbackurl))
                            {
                                e.Cancel = true;
                                childwindow.IsOpen = false;
                                var query = ParseQuesrString(e.Uri.Query.TrimStart('?'));
                                GetAccessToken(callback, c, query["oauth_verifier"]);
                            }
                        };
                    }
                    else
                    {
                        callback(null);
                    }
                });
            });
        }

        private Dictionary<string, string> ParseQuesrString(string str)
        {
            Dictionary<string, string> dic = new Dictionary<string, string>();
            foreach (var item in str.Split('&'))
            {
                string[] kv = item.Split('=');
                if (kv.Length == 2)
                {
                    dic.Add(kv[0], kv[1]);
                }
            }
            return dic;
        }

        private void GetAccessToken(Action<OAuthAccessToken> callback, OAuthRequestToken requestToken, string verifier)
        {
            var requester = new TokenObtainRequest("http://open.tianya.cn/oauth/access_token.php");
            requester.Params.Add(new ParamPair(Constants.OAuthToken, requestToken.Token));
            requester.Params.Add(new ParamPair(Constants.OAuthVerifier, verifier));
            requester.Secret = requestToken.Secret;
            requester.Request((status, msg) =>
            {
                if (status == WebExceptionStatus.Success)
                {
                    var query = ParseQuesrString(msg);
                    //oauth_token=bcda532efbb8b2da32f5a0f7ad645eb604fb35344&oauth_token_secret=32dcceccc0bd97c28ce43ab1b0d84def
                    //var accessTokenMatch = Regex.Match(msg, APIConfig.RetrieveAccessTokenPattern, RegexOptions.IgnoreCase);
                    //if (!accessTokenMatch.Success)
                    //    throw new Exception("Failed to retrieve access token.");
                    var accessToken = query["oauth_token"];
                    var accessTokenSecret = query["oauth_token_secret"];
                    callback(new OAuthAccessToken() { Token = accessToken, Secret = accessTokenSecret });
                }
                else
                    callback(null);
            });
        }
        #endregion



        public void Execute<T>(HttpGet<T> request, Action<T> callBack) where T : BaseResponse
        {
            request.Params.Add("appkey", G.Net.Oauth.OauthConfiger.AppKey);
            request.Params.Add("oauth_token", G.Net.Oauth.OauthConfiger.AccessToken.Token);
            request.Params.Add("oauth_token_secret", G.Net.Oauth.OauthConfiger.AccessToken.Secret);
            string timestamp = DateTime.Now.ToString();
            request.Params.Add("timestamp", timestamp);
            string signString = timestamp + G.Net.Oauth.OauthConfiger.AppKey + G.Net.Oauth.OauthConfiger.AccessToken.Token + G.Net.Oauth.OauthConfiger.AccessToken.Secret + G.Net.Oauth.OauthConfiger.AppSecret;
            string sign = MD5.GetHashString(signString);
            request.Params.Add("tempkey", sign);
            request.Request((status, msg) =>
            {
                DoResponse<T>(status, msg, callBack);
            });
            //var c = request.RequestAsync();

        }

        private void DoResponse<T>(WebExceptionStatus status, string msg, Action<T> callBack) where T : BaseResponse
        {
            if (status == WebExceptionStatus.Success)
            {
                ParseToObj<T>(msg, callBack);
            }
            else
            {
                UIElement uielment = callBack.Target as UIElement;
                if (uielment != null)
                {
                    uielment.Dispatcher.BeginInvoke(() =>
                    {
                        G.Navigate.PhoneApplicationPageHelp.GetBasePage().ShowState(string.Format("{0}:{1}", status.ToString(), msg));
                    });
                }
                T rsp = Activator.CreateInstance<T>();
                rsp.IsError = true;
                rsp.Body = msg;
                callBack(rsp);
            }
        }


        JsonParser jsonParser = new JsonParser();
        private void ParseToObj<T>(string body, Action<T> callBack) where T : BaseResponse
        {
            T rsp = null;
            //if (body.StartsWith("exception"))
            //{
            //    rsp = Activator.CreateInstance<T>();
            //    rsp.IsError = true;
            //    string[] strs = body.Split(':');
            //    rsp.Body = string.Format("{0}\r\n{1}", strs[1], strs[2]);
            //    if (callBack.Target is UIElement)
            //    {
            //        (callBack.Target as UIElement).Dispatcher.BeginInvoke(() =>
            //        {
            //            MessageBox.Show(rsp.Body, "出Bug啦！", MessageBoxButton.OK);
            //        });
            //    }
            //    callBack(rsp);
            //    return;
            //}
            try
            {
                JsonSerializerPathAttribute att = Attribute.GetCustomAttribute(typeof(T), typeof(JsonSerializerPathAttribute)) as JsonSerializerPathAttribute;
                if (att == null)
                {
                    rsp = jsonParser.Parse<T>(body);
                }
                else
                {
                    object obj = jsonParser.Parse(att.PropertyType, body);
                    rsp = Activator.CreateInstance<T>();
                    typeof(T).GetProperty(att.PropertyName).SetValue(rsp, obj, null);
                }
                rsp.Body = body;
                callBack(rsp);
            }
            catch (Exception ex)
            {
                if (callBack.Target is UIElement)
                {
                    (callBack.Target as UIElement).Dispatcher.BeginInvoke(() =>
                    {
                        MessageBox.Show(ex.Message, "数据解析出错！", MessageBoxButton.OK);
                    });
                }
                if (rsp == null)
                {
                    rsp = Activator.CreateInstance<T>();
                }
                rsp.IsError = true;
                rsp.Body = body;
                callBack(rsp);
            }

        }

    }
}
